<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>summer document</title>
    <!-- Bootstrap core CSS -->
    <link href="../bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link href="../css/blog.css" rel="stylesheet">
    <link href="../css/desert.css" rel="stylesheet">
</head>

<body onload="PR.prettyPrint()">

<div class="blog-masthead">
    <div class="container">
        <nav class="blog-nav">
            <a class="blog-nav-item active" href="#">文档</a>
            <a class="blog-nav-item" href="http://git.oschina.net/xiwa/summer">源码</a>
            <a class="blog-nav-item" href="http://git.oschina.net/xiwa/summer-sample">示例</a>
            <a class="blog-nav-item" href="https://git.oschina.net/mgfireworks/mgplatform/tree/dev/">案例</a>
        </nav>
    </div>
</div>

<div class="container">

    <div class="blog-header">
        <br/>
        <br/>
        <h1 class="blog-title">summer框架文档</h1>
        <br/>
        <br/>
    </div>

    <div class="row">

        <div class="col-sm-2 blog-sidebar">
            <div class="sidebar-module">
                <h4>目录</h4>
                <ol class="list-unstyled">
                    <li>
                        <a href="#start">起步</a>
                        <ol>
                            <li><a href="#app-struct">项目结构</a></li>
                            <li><a href="#app-config">项目配置</a></li>
                            <li><a href="#app-package">程序打包</a></li>
                        </ol>
                    </li>
                    <li>
                        <a href="#database">数据库操作</a>
                        <ol>
                            <li><a href="#db-orm-setup">单表orm准备步骤</a></li>
                            <li><a href="#db-orm-query">单表orm查询</a></li>
                            <li><a href="#db-orm-insert">单表orm新增</a></li>
                            <li><a href="#db-orm-update">单表orm修改</a></li>
                            <li><a href="#db-orm-delete">单表orm删除</a></li>
                            <li><a href="#db-sqlId-cuid">sqlId配置和规则</a></li>
                            <li><a href="#db-sqlid-query">根据sqlId查询</a></li>
                            <li><a href="#db-sqlid-combine">根据sqlId组合查询</a></li>
                            <li><a href="#db-sqlid-cascade">根据sqlId级联查询</a></li>
                            <li><a href="#db-sqlid-iud">根据sqlId增、删、改</a></li>
                        </ol>
                    </li>
                    <li>
                        <a href="#data-valid">数据验证</a>
                    </li>
                    <li>
                        <a href="#view-template">视图和模板引擎</a>
                        <ol>
                            <li><a href="#view-json">json视图</a></li>
                            <li><a href="#view-excel">excel视图</a></li>
                            <li><a href="#view-rythm">rythm视图模板引擎</a></li>
                        </ol>
                    </li>
                </ol>
            </div>
        </div><!-- /.blog-sidebar -->

        <div class="col-sm-10 blog-main">

            <h2 class="blog-post-title">框架简介</h2>
            <p>
                此项目目的在于提供一个简化、简洁、迅速的开发架构。
            </p>
            <p>
                它是基于spring boot和spring mvc高度封装的快速开发框架，数据库操作工具summerDao是基于jdbcTemplate高度封装简化、拥有超级简单实用的ORM功能、和ibatis一样强大但更简单、无需映射配置的dao工具，视图层采用的是Rythm(最简洁的java模板引擎：http://rythmengine.org)。
                可以用它来做web项目、微服务、socket服务，且同一套代码同时兼容这三种方式。
            </p>
            <h2 class="blog-post-title">特点、特性</h2>
            <ol>
                <li>基本建立在spring一套组件之上采用注解方式，方便快捷无需学习其它框架。</li>
                <li>数据库操作简单，只需写好sql即可，自动与指定实体bean进行绑定。</li>
                <li>无须编写DAO，无须动态拼sql，查询条件智能组装。</li>
                <li>支持单表ORM，零配置无需注解，实体类生成。</li>
                <li>支持灵活的级联查询。</li>
                <li>支持多数据源，不同数据库。</li>
                <li>自动分页支持，无须编写任何与分页相关的代码。</li>
                <li>统一的异常捕获，无须编写异常处理代码。</li>
                <li>采用hibernate的注解数据验证，同时应用于前台验证无须编写JS代码。</li>
                <li>支持json和页面输出自动转换，异常包装确保输出的都是可用的json。</li>
                <li>页面使用Rythm提供的Razor语法，基本与java语法一致、无标签，极少的学习成本。</li>
                <li>表单自动JS验证，列表自动分页。</li>
                <li>action支持多值返回，彻底告别Model。</li>
                <li>默认使用cookies代替session，轻松实现应用集群，开发时重启程序session不会丢失。</li>
                <li>action支持使用RequestMapping的name指定视图名。</li>
            </ol>

            <div class="blog-post">
                <a name="start"></a>
                <h2 class="blog-post-title">起步</h2>
                <p class="blog-post-meta">项目结构、配置、打包</p>
                <a name="app-struct"></a>
                <h3>项目结构</h3>
                <pre class="prettyprint">
├─config 						//配置文件目录
│  ├─application.properties 				//主配置文件
│  ├─logback-spring.xml 				//日志配置
│  ├─sql-Area.xml					//sql配置文件(多个)
├─html 						//页面目录
│  ├─index.html 					//首页
│  ├─main_template.html 				//页面模板
│  ├─statc 						//静态资源目录(js、css、图片等)
│  ├─area 						//业务模块area
│  └─static 						//静态资源目录
└─src
    └─main
        ├─assembly
        │  └─assembly.xml                   //打包配置文件
        ├─scripts
        │  ├─run.sh                         //linux下程序启动脚本
        │  └─run.bat                        //windows下程序启动脚本
        ├─java
        │  ├─main
        │  │   ├─App.java 				//应用启动类
        │  │   └─AppTool.java 				//工具应用启动类
        │  └─summer
        │       └─sample
        │           ├─MainController.java		//主控制器类
        │           ├─ControllerAspect.java		//控制器拦截处理类
        │           └─area
        │               ├─db 				//自动生成实体类目录
        │               │  └─Address.java 		//自动生成的实体类
        │               ├─model			//业务模型目录
        │               └─AreaController.java		//业务Area控制器类(这里简化了没加service类)
        └─resources					//资源目录
                └─summer
                    └─sample
                        └─area
                            └─db
                                └─Address_create.sql	//建表脚本(类名_create.sql)
</pre>
                <a name="app-config"></a>
                <h3>项目配置</h3>
                <p>请参考<a target="_blank" href="http://git.oschina.net/xiwa/summer-sample">http://git.oschina.net/xiwa/summer-sample</a>使用熟悉的ide建一个普通的java project，并配置好相应依赖。</p>
                <h4>1.启动类App.java</h4>
<pre class="prettyprint">
@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
@SpringBootApplication(scanBasePackages={"summer.sample"})
@Configuration()
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class App extends WebApp
{
    public static void main( String[] args )
    {
        Config.dbBeanScanFilter=".*sample.*db";//配置建表脚本目录
        SpringApplication.run(App.class);
    }

    @Bean
    public IBeanMapperRule getBeanMapperRule(){
        return new UnderlinedBeanMapperRule(); //设置下划线风格列名转驼峰属性名
    }
}
</pre>
                <h4>2.app工具AppTool.java</h4>
<pre class="prettyprint">
//自动生成实体类
new EntityGenerator(
    new UnderlinedBeanMapperRule(""), //列名属性名映射风格
    new MysqlTypeMapperRule()         //配置为mysql数据类型
).autoGenEntity("/src/main/java","src/main/resources"); //指定源码和资源目录
</pre>

                 <h4>3.配置文件application.properties</h4>
<pre class="prettyprint">
datasource.url=jdbc:mysql://localhost:3306/lott_chart?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
datasource.driverClassName=com.mysql.jdbc.Driver
datasource.username=root
datasource.password=123456

logging.path=log
logging.config=config/logback-spring.xml

#server.port=8080
server.tomcat.docbase=./html
#
template.home=./html
template.mode=dev
</pre>

                <h4>4.配置controller拦截器</h4>
<pre class="prettyprint">
@Aspect
@Component
public class ControllerAspect extends WebApplicationObjectSupport{

    /**
    * 拦截action执行返回结果
    */
    @Pointcut("execution(public * summer.sample..*.*Controller.*(..))")
    public void catchActionExecuteResult(){}

    /**
    * 拦截action执行返回结果
    */
    @Around("catchActionExecuteResult()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        return ControllerAspectTool.around(pjp, getApplicationContext());
    }
}
</pre>
                <a name="app-package"></a>
                <h3>程序打包</h3>
                <p>
                    请参考pom.xml和assembly.xml配置，如果需要增加或减少依赖包、修改依赖包版本，请修改pom.xml和run.sh/run.bat中对应的jar包名称。
                </p>
                <p>
                    使用ide菜单或执行maven命令：<code>clean package -Dmaven.test.skip=true -Dfile.encoding=UTF-8</code>打包
                </p>
            </div><!-- 起步 -->

            <div class="blog-post">
                <a name="database"></a>
                <h2 class="blog-post-title">数据库操作</h2>
                <p class="blog-post-meta">单表orm、增、删、改、查</p>
                <h2>单表orm操作</h2>
                <blockquote>
                    <a name="db-orm-setup"></a>
                    <h3>单表orm准备步骤</h3>
                    <h4>1、 在App.java中配置自动生成实体类存放目录
                        <pre class="prettyprint">
Config.dbBeanScanFilter=".*sample.*db";</pre>
                    </h4>
                    <h4>2、在App.java中配置生成实体类规则</h4>
                    <pre class="prettyprint">
@Bean
public IBeanMapperRule getBeanMapperRule(){
    return new UnderlinedBeanMapperRule();
}</pre>
                    <p>系统提供了2种映射规则：</p>
                    <p>DefaultBeanMapperRule-和表字段名保持一致</p>
                    <p>UnderlinedBeanMapperRule-将下划线风格的字段名称转换为驼峰风格的bean属性名</p>
                    <h4>3、添加自动生成实体类代码</h4>
                    <pre class="prettyprint">
new EntityGenerator(
    new UnderlinedBeanMapperRule(""),
    new MysqlTypeMapperRule()   //指定数据类型映射规则
).autoGenEntity("/src/main/java","src/main/resources");</pre>
                    <p>系统提供了mysql数据库的数据类型映射规则，其它数据库请自行添加。</p>
                    <h4>4、执行AppTool启动自动实体生成（不关闭，一旦有脚本更新或添加就会生成对应的实体类文件）</h4>
                    <h4>5、使用数据库工具生成Bean_create.sql建表脚本放在resources对应模块db目录</h4>
                    <p>
                        如，生成Address_create.sql放在resources/summer/sample/area/db目录，此时可以看到在对应包summer.sample.area.db中已经生成了Address.java文件。
                    </p>
                    <p>单表orm关系映射是依靠Bean_create.sql来完成的，生成好实体类后请不要删除。</p>
                </blockquote>
                <a name="db-orm-query"></a>
                <h3>单表orm查询：list(Class elementType, Object... args)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public List&lt;Address&gt; getAddresses(Address a){
    return dao.list(Address.class,a);
}
</pre>
                    <p><code>elementType</code>要返回的实体类型。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>

                <h3>单表orm分页查询</h3>
                <blockquote>
<pre class="prettyprint">
@Controller
@RequestMapping("/area")
public class AreaController {
    @Autowired
    BaseDao dao;
    @RequestMapping("/getAddresses")
    public List&lt;Address&gt; getAddresses(){
        return dao.list(Address.class);
    }
}
</pre>
                    <p>和普通查询一样，只需要在访问时带上page或pageSize参数即可，如：area/getAddresses.json?page=1</p>
                    <p>注：同一个请求中同时只能存在一个查询需要分页，其它查询不需要分页的要使用all。</p>
                </blockquote>
                <h3>单表orm排序查询：list(Class elementType, OrderBy orderBy, Object... args)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public List&lt;Address&gt; getAddresses(Address a){
    return dao.list(Address.class, dao.order().desc("addressId"), a);
}
</pre>
                    <p><code>elementType</code>要返回的实体类型。</p>
                    <p><code>orderBy</code>排序信息，可链式调用。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>

                <h3>单表orm查询所有：all(Class elementType, Object... args)</h3>
                <blockquote>同list方法，但不支持分页查询</blockquote>

                <h3>单表orm取单条记录：get(Class type, Object... args)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public Address getAddress(Address a){
    return dao.get(Address.class,a);
}
</pre>
                    <p><code>type</code>要返回的实体类型。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>
                <a name="db-orm-insert"></a>
                <h3>单表orm新增：int insert(T bean)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public int addAddresses(Address address){
    return dao.insert(address);
}
</pre>
                    ps：<p>如果bean中包含了自增字段，insert插入成功后会自动将自增id填充回bean。</p>
                    <p>自动去除insert语句中为空的字段。</p>
                </blockquote>
                <a name="db-orm-update"></a>
                <h3>单表orm按主键更新：int update(T bean)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public int editAddresses(Address address){
    return dao.update(address);
}
</pre>
                </blockquote>
                <h3>单表orm按条件更新：int update(T bean, ConditionEntity condition)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public int editAddresses(Address address){
    return dao.update(address,dao.ce().set("条件名",条件值));
}
</pre>
                    <p>ps：自动去除update语句中为空的set字段。</p>
                </blockquote>
                <a name="db-orm-delete"></a>
                <h3>单表orm按主键删除：int delete(T bean)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public int delAddress(Address address){
    return dao.delete(address);
}
</pre>
                </blockquote>
                <h3>单表orm按条件删除：int delete(Class<T> type, ConditionEntity condition)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public int delAddress(Address address){
    return dao.delete(Address.class,dao.ce().set("addressId",1);
}
</pre>
                </blockquote>

                <a name="db-sqlId-cuid"></a>
                <h2>根据sqlId增删改查</h2>
                <blockquote>
                    <h4>1.sql配置文件，文件名：sql-名称.xml</h4>
<pre class="prettyprint">
&lt;SqlConfig&gt;
	&lt;query&gt;
		&lt;sql id="全局唯一id"&gt;
			sql语句
		&lt;/sql&gt;
	&lt;/query&gt;

	&lt;insert&gt;
	&lt;/insert&gt;

	&lt;update&gt;
	&lt;/update&gt;

	&lt;delete&gt;
	&lt;/delete&gt;
&lt;/SqlConfig&gt;</pre>
                    <p>sql配置文件中必须包含query、insert、update、delete四个节点，分别放置不同语义的sql。</p>
                    <h4>2.sql语句格式</h4>
<pre class="prettyprint">
    /*
    多行注释，支持任意合法sql语句，支持多条sql写在一起
    */
SELECT
    a.`areaId`, //单行注释
    a.`areaName`,
    a.areaLevel, //字段名可用`包围
    a.`parentId`,
    b.`areaName` as parentArea //可取别名
FROM
    `mg_area` a left join #tableName# b //可任意关联，可动态设置表名
    on a.parentId = b.areaId
where //大小写不限
    a.areaId = :areaId //参数以:xx的形式表示
    and a.areaName like %:areaName% //like参数无须特别处理
    and	a.areaLevel = :areaLevel //自动删除值为空的参数
    and a.parentId in(:pids) //in参数直接传数组
    order by parentId , areaId
</pre>
                </blockquote>
                <a name="db-sqlid-query"></a>
                <h3>根据sqlId查单条记录：T get(String sql, Class type, Object... args)</h3>
                <blockquote>
<pre class="prettyprint">
@Autowired
BaseDao dao;
public Address getAddress(Address a){
    return dao.get("getAddress",Address.class,a);
}

&lt;sql id="getAddress"&gt;
   SELECT
    `address_id`,
    `address`,
    `address2`,
    `district`,
    `city_id`,
    `postal_code`,
    `phone`,
    `last_update`
   FROM `address`
   where
    address_id=:addressId and
    city_id=:cityId and
    address like %:address% and
    postal_code=:postalCode
&lt;/sql&gt;
</pre>
                    <p><code>sql</code>sqlId或完整sql语句。</p>
                    <p><code>type</code>要返回的实体类型。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>

                <h3>根据sqlId查询：list(String sql, Class elementType, Object... args)</h3>
                <blockquote>
                    sql同上，支持自动分页查询。
                    <p>当需要分页查询时，只需要在访问时带上page或pageSize参数即可，如：area/getAddresses.json?page=1</p>
                    <p>注：同一个请求中同时只能存在一个查询需要分页，其它查询不需要分页的要使用all。</p>
                    <p><code>sql</code>sqlId或完整sql语句。</p>
                    <p><code>elementType</code>要返回集合中的实体类型。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>

                <h3>根据sqlId分页查询：page(String sql, Class elementType, int pageSize, int page, Object... args)</h3>
                <blockquote>
                    sql同上，专门的分页查询。
                    <p><code>sql</code>sqlId或完整sql语句。</p>
                    <p><code>elementType</code>要返回集合中的实体类型。</p>
                    <p><code>pageSize</code>分页大小。</p>
                    <p><code>page</code>当前页码。</p>
                    <p><code>args</code>查询条件，可以是任意多个bean或ConditionEntity对象。</p>
                </blockquote>
                <h3>根据sqlId强制查询所有：all(String sql, Class elementType, Object... args)</h3>
                <blockquote>
                    同list方法，但不支持分页查询，强制查询所有。
                </blockquote>
                <a name="db-sqlid-combine"></a>
                <h3>根据sqlId组合查询</h3>
                <blockquote>
                    <p>为一个sql节点添加多个子sql，并设置子sql的name属性，代码中根据业务场景使用"+"连接父sqlId和子sql的name作为一个完全的sql执行。</p>
                    sql配置
<pre class="prettyprint">
&lt;sql id="getActors"&gt;
SELECT `actor_id`,
    `first_name`,
    `last_name`,
    `last_update`
FROM `actor`
    &lt;sql name="condition1"&gt;
    WHERE
    `first_name` like %:firstName%
    &lt;/sql&gt;
    &lt;sql name="condition2"&gt;
    WHERE
    length(first_name)= :len OR
    `last_name` like %:lastName%
    &lt;/sql&gt;
    &lt;sql name="condition3"&gt;
    where
    actor_id in(:actorIds)
    &lt;/sql&gt;
&lt;/sql&gt;
</pre>
                    代码
<pre class="prettyprint">
//Actor.java
@Data
public class Actor {
    private Short actorId;
    private String firstName;
    private String lastName;
    private Timestamp lastUpdate;
}
//ActorVo.java
@Data
public class ActorVo extends Actor {
    private Integer len;
}
//Service
public List<Actor> getActors2(ActorVo actorVo){
    return dao.list(
        //当firstName不为空时使用condition1的查询条件，否则使用condition2的查询条件
        "getActors+condition"+(actorVo.getFirstName()!=null?1:2),
        Actor.class,
        actorVo
    );
}
</pre>
                </blockquote>
                <a name="db-sqlid-cascade"></a>
                <h3>根据sqlId级联查询</h3>
                <blockquote>
                    <h4>1.一对一级联查询</h4>
                    <p>创建实体类：Address.java、City.java、AddressVo.java</p>
<pre class="prettyprint">
@Data
public class Address {
    private java.lang.Short addressId;
    private java.lang.String address;
    private java.lang.String address2;
    private java.lang.String district;
    private java.lang.Short cityId;
    private java.lang.String postalCode;
    private java.lang.String phone;
    private java.sql.Timestamp lastUpdate;
}

@Data
public class City {
    private java.lang.Short cityId;
    private java.lang.String city;
    private java.lang.Short countryId;
    private java.sql.Timestamp lastUpdate;
}

@Data
public class AddressVo extends Address {
    private City city; //一对一city属性
}
</pre>
                    <p>sql配置，使用子sql标签，写上要级联查询的sql，并设置prop为对应级联的属性名。</p>
<pre class="prettyprint">
&lt;sql id="getAddress"&gt;
        SELECT
            `address_id`,
            `address`,
            `address2`,
            `district`,
            `city_id`,
            `postal_code`,
            `phone`,
            `last_update`
        FROM `address`
        WHERE
        city_id=:cityId
        &lt;sql prop="city"&gt; //一对一关联city属性
            SELECT
                `city_id`,
                `city`,
                `country_id`,
                `last_update`
            FROM `city`
            WHERE
            city_id=:cityId
    &lt;/sql&gt;
&lt;/sql&gt;
</pre>
                    <p>使用"sqlId<-prop"作为sqlId进行查询。</p>
<pre class="prettyprint">
public AddressVo getAddress(Address address){
    return dao.get("getAddress<-city",AddressVo.class,address);
}</pre>
                </blockquote>

                <h4>2.一对多级联查询</h4>
                <blockquote>
                <p>创建实体类：Address.java、City.java、CityVo.java</p>
<pre class="prettyprint">
@Data
public class CityVo extends City {
    private List&lt;Address&gt; addresses; //一对多addresses属性
}</pre>
                <p>sql配置，使用子sql标签，写上要级联查询的sql，并设置prop为对应级联的属性名。</p>
<pre class="prettyprint">
&lt;sql id="getCity"&gt;
    SELECT
        `city_id`,
        `city`,
        `country_id`,
        `last_update`
    FROM `city`
    WHERE
    city_id=:cityId
    &lt;sql prop="addresses"&gt; //一对多关联addresses属性
        SELECT
            `address_id`,
            `address`,
            `address2`,
            `district`,
            `city_id`,
            `postal_code`,
            `phone`,
            `last_update`
        FROM `address`
        WHERE
        city_id=:cityId
    &lt;/sql&gt;
&lt;/sql&gt;
</pre>
                <p>使用"sqlId<-prop"作为sqlId进行查询。</p>
<pre class="prettyprint">
public CityVo getCity(City city){
    return dao.get("getCity<-addresses",CityVo.class,city);
}</pre>
                </blockquote>
                <a name="db-sqlid-iud"></a>
                <h3>根据sqlId新增、修改、删除：int update(String sql, Object... args)</h3>
                <blockquote>
                    <p>新增、修改、删除都使用update方法</p>
<pre class="prettyprint">
&lt;sql id="addArea"&gt;
INSERT INTO
`mg_area`
(
    `areaId`,
    `areaName`,
    `areaLevel`,
    `parentId`
)VALUES(
    :areaId,
    :areaName,
    :areaLevel,
    :parentId
)
&lt;/sql&gt;
//代码：
    update("addArea",area);
=================================

&lt;sql id="editArea">
    UPDATE
    `mg_area`
SET
    `areaId` = :areaId,
    `areaName` = :areaName,
    `areaLevel` = :areaLevel,
    `parentId` = :parentId
WHERE
    `areaId` = :areaId
&lt;/sql&gt;
//代码：
    update("editArea",area);
=================================
&lt;sql id="delArea"&gt;
DELETE FROM
    `mg_area`
WHERE
    `areaId` = :areaId
&lt;/sql&gt;
//代码：
    update("delArea",area);
</pre>
                    <p>ps：自动去除update语句中为空的set字段。</p>
                </blockquote>
            </div>
            <div class="blog-post">
                <a name="data-valid"></a>
                <h2 class="blog-post-title">数据验证</h2>
                <h3>1.给待验证的bean加上验证注解</h3>
<pre class="prettyprint">
public class Band {
    /**
    * 品牌编号
    */
    @NotNull(message="品牌编号不能为空")
    private Integer bandId;

    /**
    * 品牌名称
    */
    @NotNull(message="品牌名称不能为空")
    private String bandName;
}
</pre>
                <p>使用hibernate的验证器，见：<a target="_blank" href="http://hibernate.org/validator">http://hibernate.org/validator</a></p>
                <h3>2.执行验证</h3>
                <p>使用@ParamValid注解在action中自动验证</p>
<pre class="prettyprint">
/**
* 提交添加品牌
*/
@PostMapping("/add")
public void postAdd(@ParamValid Band p){
    bandService.addBand(p);
}
</pre>
                <p>使用BeanValidator.valid验证</p>
<pre class="prettyprint">
/**
* 添加品牌
*/
public void addBand(Band p) throws BusinessException {
    BeanValidator.valid(p);
    update("addBand",p);
}
</pre>
                <h3>3.显示验证结果</h3>
                在页面中使用<code>@errors()</code>标签显示验证错误信息，详见模板引擎部分。
            </div>

            <div class="blog-post">
                <a name="data-valid"></a>
                <h2 class="blog-post-title">视图和模板引擎</h2>
                <a name="view-json"></a>
                <h3>1.json视图</h3>
                <blockquote>
                    内置json视图，当使用.json后缀访问或访问页面不存在时输出json数据。
                    <p>统一json格式，确保后台发生错误或异常时都能返回正确的、js可处理的json格式数据。</p>
                    成功：
<pre class="prettyprint">
{
    "result" : true,
    "data" : {
        "属性1" : 值1,
        "属性2" : 值2,
       ...
    }
}
</pre>
                    失败(异常)：
<pre class="prettyprint">
{
    "result" : false,
    "data" : "xxx错误信息..."
}
</pre>
                </blockquote>

                <a name="view-excel"></a>
                <h3>2.excel视图</h3>
                <blockquote>
                    后续添加
                </blockquote>

                <a name="view-rythm"></a>
                <h3>3.rythm视图</h3>
                <blockquote>
                    <p>详细文档见：<a target="_blank" href="http://rythmengine.org">rythmengine.org</a></p>
                </blockquote>
            </div>

        </div><!-- /.blog-main -->

    </div><!-- /.row -->

</div><!-- /.container -->

<footer class="blog-footer">
    <p>
        <a href="#">Back to top</a>
    </p>
</footer>

<script src="../js/jquery.min.js"></script>
<script src="../bootstrap/js/bootstrap.min.js"></script>
<script src="../bootstrap/js/run_prettify.js?lang=css&amp;skin=desert"></script>
</body>
</html>

